#![allow(warnings)]
use std::fmt;

use super::{Slot, Object};



// type LocalVars = Vec<Slot>;
// 局部变量表（Local Variables Table）是一组变量值的存储空间，用于存放方法参数和方法内部定义的局部变量。
// #[derive(Debug)]
pub struct LocalVars {
    slots: Vec<Slot>, // 局部变量表的容量以变量槽（Variable Slot）为最小单位
}

impl LocalVars {
    pub fn new_local_vars(max_locals: usize) -> LocalVars {
        LocalVars {
            slots: (0..max_locals).map(|_| Slot::default()).collect()
        }
    }

    pub fn set_int(&mut self, index:usize, val: i32) {
        self.slots[index].set_num(val);
    }

    pub fn get_int(&self, index: usize) -> i32 {
        self.slots[index].get_num()
    }

    pub fn set_float(&mut self, index: usize, val: f32) {
        let bytes = val.to_be_bytes();
        self.slots[index].set_num(i32::from_be_bytes(bytes));
    }

    pub fn get_float(&self, index: usize) -> f32 {
        let bytes = self.slots[index].get_num().to_be_bytes();
        f32::from_be_bytes(bytes)
    }

    pub fn set_long(&mut self, index: usize, val: i64) {
        self.slots[index].set_num((val >> 32) as i32);
        self.slots[index + 1].set_num(val as i32);
    }

    pub fn get_long(&self, index: usize) -> i64 {
        // 小转大，i32 -> i64
        // 如果源数据是无符号的，则进行零扩展(zero-extend)
        // 如果源数据是有符号的，则进行符号扩展(sign-extend)
        let high = self.slots[index].get_num() as i64;
        let low = self.slots[index + 1].get_num() as i64;
        (high << 32) | (low & 0xffffffff)
    }

    pub fn set_double(&mut self, index: usize, val: f64) {
        let bytes = val.to_be_bytes();
        self.set_long(index, i64::from_be_bytes(bytes));
    }

    pub fn get_double(&self, index: usize) -> f64 {
        let bytes = self.get_long(index).to_be_bytes();
        f64::from_be_bytes(bytes)
    }

    pub fn set_ref(&mut self, index: usize, _ref: Option<*mut Object>) {
        self.slots[index].set_ref(_ref);
    }

    pub fn get_ref(&self, index: usize) -> Option<*mut Object> {
        self.slots[index].get_ref()
    }

    pub fn get_this(&self) -> Option<*mut Object> {
        self.get_ref(0)
    }

    pub fn get_boolean(&self, index: usize) -> bool {
        self.get_int(index) == 1
    }

    pub fn set_slot(&mut self, index: usize, slot: Slot) {
        self.slots[index] = slot;
    }

    pub fn get_slot(&self, index: usize) -> Slot {
        self.slots[index].clone()
    }

}

impl fmt::Display for LocalVars {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let string:Vec<String> = self.slots.iter()
            .map(|slot| format!("{}", slot))
            .collect();
        write!(f, "LocalVars: slots: [{}]", string.join(","))
    }
}
